Skip to content

Propagate Function Invocations#216

Open
rcosta358 wants to merge 12 commits into
mainfrom
function-invocation-simplification
Open

Propagate Function Invocations#216
rcosta358 wants to merge 12 commits into
mainfrom
function-invocation-simplification

Conversation

@rcosta358
Copy link
Copy Markdown
Collaborator

@rcosta358 rcosta358 commented May 9, 2026

Description

This PR allows function invocations to be on the LHS of mappings (instead of just variables).
This works by using the function string representation as a key in the variable resolver map, meaning they behave as if they were variables.
For example, func(a) == func(b) && func(b) == 1func(a) == 1.

Example

Before

State Refinement Error: Expected state size(stack²⁹⁵) > 0 but found size(stack²⁹⁵) == size(stack²⁹⁴) - 1 && size(stack²⁹⁴) == size(stack²⁹²) + 1 && size(stack²⁹²) == 0

After

State Refinement Error: Expected state size(stack²⁹⁴) > 0 but found size(stack²⁹⁴) == 0

Related Issue

None.

Type of change

  • Bug fix
  • New feature
  • Documentation update
  • Code refactoring

Checklist

  • Added tests in ExpressionSimplifierTest
  • mvn test passes locally
  • Updated docs/README if behavior or API changed

@rcosta358 rcosta358 requested a review from CatarinaGamboa May 9, 2026 21:48
@rcosta358 rcosta358 self-assigned this May 9, 2026
@rcosta358 rcosta358 added enhancement New feature or request simplification Related to the simplification of expressions labels May 9, 2026
@rcosta358 rcosta358 changed the title Function Invocation Simplification Propagate Function Invocations May 10, 2026
@rcosta358 rcosta358 changed the base branch from improve-simplification to main May 11, 2026 13:30
Copy link
Copy Markdown
Collaborator

@CatarinaGamboa CatarinaGamboa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is using strings here the best idea? Couldn't we use the expressions?
Also, we need more examples.
I was wondering, for the test suite we have already, we dont check the simplification right? we only have tests for "if an error in that line of type T", should we plan for a startegy to also have more tests for simplification?

Expression left = be.getFirstOperand();
Expression right = be.getSecondOperand();
String leftKey = substitutionKey(left);
String rightKey = substitutionKey(right);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is using strings for substitution really the best approach?

ValDerivationNode result = ExpressionSimplifier.simplify(fullExpression);

assertEquals("size(x3) == 0", result.getValue().toString());
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need a couple more tests for this, I'm not very convinced

@rcosta358
Copy link
Copy Markdown
Collaborator Author

rcosta358 commented May 11, 2026

The mapping we had was variable nameexpression, so using the string representation of the function invocation as a "variable" made sense to me, and I think that's enough.
Using a mapping expressionexpression seems a bit weird to me.
Regarding the tests, we have separate tests for the simplification, in ExpressionSimplifierTest and VariableResolverTest.

@CatarinaGamboa
Copy link
Copy Markdown
Collaborator

The mapping we had was variable nameexpression, so using the string representation of the function invocation as a "variable" made sense to me, and I think that's enough. Using a mapping expressionexpression seems a bit weird to me. Regarding the tests, we have separate tests for the simplification, in ExpressionSimplifierTest and VariableResolverTest.

Can we improve those tests to show the string?
like:

  @Test
  void testFunctionInvocationEqualitiesPropagateTransitively() {
     String toTest = "size(x3) == size(x2) - 1 && size(x2) == size(x1) + 1 && size(x1) == 0";
      Expression expr = RefinementsParser.createAST(toTest, "");

      ValDerivationNode result = ExpressionSimplifier.simplify(expr);

      assertEquals("size(x3) == 0", result.getValue().toString());
  }

its pretty hard to understand the tests the way they are now

@rcosta358
Copy link
Copy Markdown
Collaborator Author

Will do.

@rcosta358 rcosta358 requested a review from CatarinaGamboa May 11, 2026 14:22
Copy link
Copy Markdown
Collaborator

@CatarinaGamboa CatarinaGamboa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would still prefer the map Expr->Expr than String->Expr I think it makes more sense, and we can use equals so I dont think it adds complexity and its more accurate.
But this should work for now if you want to take care of that in another PR, or ask for someone else's opinion

} else if (left instanceof Var var && canSubstitute(var, right)) {
map.put(var.getName(), right.clone());
} else if (left instanceof FunctionInvocation && !right.toString().contains(leftKey)) {
map.put(leftKey, right.clone());
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this means we would not substitute something like:
f(a) == ff(a) + b

because the string on the right contains f(a) even though they are not related, right?
Ig better be conservative but we should be aware of this limitation

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, I'll replace that string check with an AST check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request simplification Related to the simplification of expressions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants